/*
 * =====================================================================================
 *
 *       Filename:  pre_thread_server.cpp
 *
 *    Description:  TCP预先创建线程服务器程序，每个线程各自accept
 *
 *        Version:  1.0
 *        Created:  2008年09月23日 15时38分19秒
 *       Revision:  none
 *       Compiler:  g++
 *
 *         Author:  ZhixiongHong (hzx), fishwarter@gmail.com
 *        Company:  Unioncast
 *
 * =====================================================================================
 */

#include "cs_common.h"

typedef struct
{
	pthread_t	thread_tid;	  	// thread_id 
	long		thread_count; 	// connections handled
}Thread;

Thread	*tptr;					// array of Thread structures; calloc'ed

int listenfd, nthreads;
socklen_t 	addrlen;
pthread_mutex_t	mlock;


pthread_mutex_t mloc = PTHREAD_MUTEX_INITIALIZER;

void thread_make(int);
void* thread_main(void *);

int main(int argc, char** argv)
{
	if( argc !=3 )	
	{
		cout << "usage: " << argv[0] << " <#port> <#children>" << endl;
		return -1;
	}
	unsigned short port = (unsigned short )atoi(argv[1]);
	nthreads = atoi(argv[2]);
	

    struct      sockaddr_in servaddr;

	signal(SIGCHLD, sig_chld);
    signal(SIGPIPE, SIG_IGN);

	listenfd = socket(AF_INET, SOCK_STREAM,0);
    if(listenfd < 0)
    {
        cout << "create listenfd error " << strerror(errno) << endl;
        return -1;
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port);
    
    const int on = 1;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    int retint = bind(listenfd, (sockaddr *)&servaddr, sizeof(servaddr));
    if( retint)
    {
        cout << "bind listenfd error: "  << strerror(errno) << endl;
        return -1;
    }
    
    retint = listen(listenfd, LISTENQ);
    if( retint)
    {
        cout << "listen error " << strerror(errno) << endl;
        return -1;
    }
	
    cout << "in " << argv[0] << "start svr at " << port << endl;
	
	tptr = (Thread* )malloc(nthreads*sizeof(Thread));
	
	for(int i = 0; i < nthreads; i++)
	{
		cout << "in main &i " << &i << endl;
		thread_make(i);	
	}

	signal(SIGINT, sig_int);

    for(; ;)
		pause();
}


void thread_make(int i)
{
	int *p = new int;
	*p = i;
	pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *)p);
	return ;
}

void* thread_main(void *arg)
{
	int 	connfd;
	socklen_t clilen;
	struct sockaddr* cliaddr;
	
	cliaddr = (struct sockaddr*)malloc(sizeof(struct sockaddr));
	int *p = (int*)arg;
	int index  = *p;
	delete p;
	printf("thread %d starting\n", index);

	for(;;)
	{
		clilen = sizeof(struct sockaddr);
		pthread_mutex_lock(&mlock);
		connfd = accept(listenfd, cliaddr, &clilen);
		pthread_mutex_unlock(&mlock);
		tptr[index].thread_count++;
		web_child(connfd);
		close(connfd);
	}
	free(cliaddr);
}

void sig_int(int signo)
{
	pr_cpu_time();
	for(int i = 0; i < nthreads; i++)
	{
		cout << "thread:  " << tptr[i].thread_tid << " thread_count = " << tptr[i].thread_count << endl;
	}
	free(tptr);	
	exit(0);
}

void sig_chld(int signo)
{

}



